package main

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/cilium/ebpf/link"
	"github.com/cilium/ebpf/perf"
)

// SSLReadEvent 对应 eBPF 中的事件结构体
type SSLReadEvent struct {
	Timestamp uint64
	PID       uint32
	TGID      uint32
	SSLFD     uint64
	BufAddr   uint64
	Len       uint64
	Comm      [16]byte
}

func main() {
	// 检查权限
	if os.Geteuid() != 0 {
		log.Fatal("此程序需要 root 权限运行")
	}

	// 加载 eBPF 程序
	objs := &sslObjects{}
	if err := loadSslObjects(objs, nil); err != nil {
		log.Fatalf("加载 eBPF 对象失败: %v", err)
	}
	defer objs.Close()

	// 查找 libssl 库
	libsslPath := findLibSSL()
	if libsslPath == "" {
		log.Fatal("未找到 libssl 库")
	}
	log.Printf("找到 libssl 库: %s", libsslPath)

	// 附加 uprobe 到 SSL_read 函数
	sslReadProbe, err := link.Uprobe(libsslPath, "SSL_read", objs.SslReadProbe, nil)
	if err != nil {
		log.Fatalf("附加 SSL_read uprobe 失败: %v", err)
	}
	defer sslReadProbe.Close()

	// 附加 uretprobe 到 SSL_read 函数
	sslReadRetProbe, err := link.Uretprobe(libsslPath, "SSL_read", objs.SslReadRetProbe, nil)
	if err != nil {
		log.Fatalf("附加 SSL_read uretprobe 失败: %v", err)
	}
	defer sslReadRetProbe.Close()

	log.Println("SSL read 监听器已启动，按 Ctrl+C 停止...")

	// 设置性能事件读取器
	rd, err := perf.NewReader(objs.Events, 4096)
	if err != nil {
		log.Fatalf("创建性能事件读取器失败: %v", err)
	}
	defer rd.Close()

	// 处理信号
	sig := make(chan os.Signal, 1)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)

	// 事件处理循环
	go func() {
		for {
			record, err := rd.Read()
			if err != nil {
				if err == perf.ErrClosed {
					return
				}
				log.Printf("读取性能事件失败: %v", err)
				continue
			}

			if record.LostSamples != 0 {
				log.Printf("丢失了 %d 个样本", record.LostSamples)
				continue
			}

			// 解析事件数据
			var event SSLReadEvent
			if err := binary.Read(bytes.NewReader(record.RawSample), binary.LittleEndian, &event); err != nil {
				log.Printf("解析事件数据失败: %v", err)
				continue
			}

			// 打印事件信息
			printEvent(&event)
		}
	}()

	// 等待信号
	<-sig
	log.Println("正在停止 SSL read 监听器...")
}

// findLibSSL 查找 libssl 库路径
func findLibSSL() string {
	possiblePaths := []string{
		"/usr/lib/x86_64-linux-gnu/libssl.so.1.1",
		"/usr/lib/x86_64-linux-gnu/libssl.so.3",
		"/usr/lib/libssl.so.1.1",
		"/usr/lib/libssl.so.3",
		"/lib/x86_64-linux-gnu/libssl.so.1.1",
		"/lib/x86_64-linux-gnu/libssl.so.3",
	}

	for _, path := range possiblePaths {
		if _, err := os.Stat(path); err == nil {
			return path
		}
	}

	// 尝试使用 ldconfig 查找
	output, err := os.ReadFile("/etc/ld.so.cache")
	if err == nil {
		// 简单的字符串搜索，实际应用中可能需要更复杂的解析
		if bytes.Contains(output, []byte("libssl")) {
			// 这里可以添加更复杂的逻辑来解析 ld.so.cache
			return "/usr/lib/x86_64-linux-gnu/libssl.so.1.1" // 默认路径
		}
	}

	return ""
}

// printEvent 打印事件信息
func printEvent(event *SSLReadEvent) {
	timestamp := time.Unix(0, int64(event.Timestamp))
	comm := string(bytes.TrimRight(event.Comm[:], "\x00"))

	fmt.Printf("[%s] PID: %d, TGID: %d, 进程: %s\n",
		timestamp.Format("15:04:05.000"),
		event.PID,
		event.TGID,
		comm)
	fmt.Printf("  SSL FD: 0x%x, 缓冲区地址: 0x%x, 长度: %d\n",
		event.SSLFD,
		event.BufAddr,
		event.Len)
	fmt.Println("---")
}
